package com.levy.effect.ioc;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.levy.effect.ioc.test.ConfTest;
import com.levy.effect.ioc.test.Test;
import com.levy.effect.ioc.utils.AutoInjectHelper;
import com.levy.effect.ioc.utils.Scaner;

public class SimpleBeanFactory implements BeanFactory {

	private ConcurrentHashMap<String, Object> name2beans = new ConcurrentHashMap<String, Object>();
	private ConcurrentHashMap<Class<?>, Object> type2beans = new ConcurrentHashMap<Class<?>, Object>();

	public SimpleBeanFactory(String propFilepath) {
		try {
			// 读取JSON配置文件
			InputStream ips = Thread.currentThread().getContextClassLoader().getResourceAsStream(propFilepath);
			InputStreamReader isreader = new InputStreamReader(ips);
			BufferedReader bufferedReader = new BufferedReader(isreader);
			StringBuilder sb = new StringBuilder();
			do {
				String readLine = bufferedReader.readLine();
				if (readLine == null)
					break;
				sb.append(readLine);
			} while (true);
			Map<String, String> props = JSON.parseObject(sb.toString(), new TypeReference<Map<String, String>>() {
			});
			String basepath = props.get("basepath");
			// 扫描指定包并注册注解Bean
			Scaner.registerBeans(type2beans, name2beans, basepath);
			// 解析配置文件的bean定义信息
			String beans = props.get("beans");
			List<BeanDefineInfo> beanDefineInfos = JSON.parseObject(beans,
					new TypeReference<java.util.List<BeanDefineInfo>>() {
					});
			// 注册配置文件中配置的bean
			for (BeanDefineInfo beanDefineInfo : beanDefineInfos) {
				String id = beanDefineInfo.getId();
				String type = beanDefineInfo.getType();
				Class<?> clazz = Class.forName(type);
				Object instance = clazz.newInstance();
				type2beans.put(clazz, instance);
				name2beans.put(id, instance);
			}
			// 配置文件依赖注入
			for (BeanDefineInfo beanDefineInfo : beanDefineInfos) {
				List<Property> properties = beanDefineInfo.getProperties();
				String id = beanDefineInfo.getId();
				Object instance = name2beans.get(id);
				for (Property prop : properties) {
					String property = prop.getProperty();
					String value = prop.getValue();
					// 值注入
					if (value != null && !"".equals(value.trim())) {
						Field field = instance.getClass().getField(property);
						if (field != null) {
							field.setAccessible(true);
							field.set(instance, value);
						}
					}
					String ref = prop.getRef();
					// 引用注入
					if (ref != null && !"".equals(ref.trim())) {
						Field field = instance.getClass().getDeclaredField(property);
						if (field != null) {
							field.setAccessible(true);
							Object refInstance = name2beans.get(ref);
							if (refInstance != null)
								field.set(instance, refInstance);
						}
					}
				}
			}
			// 注解依赖注入
			AutoInjectHelper.inject(type2beans, name2beans);
			System.out.println();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public Object getBean(String beanName) {
		return name2beans.get(beanName);
	}

	@SuppressWarnings("unchecked")
	public <T> T getBean(Class<T> type) {
		return (T) type2beans.get(type);
	}

	public static void main(String[] args) {
		SimpleBeanFactory factory = new SimpleBeanFactory("application.json");
		Test bean = factory.getBean(Test.class);
		bean.sayHi();
		ConfTest test = (ConfTest) factory.getBean("levy");
		test.sayHi();
	}

}
